<div id="maincontent">

<h1>ECMAScript 对象作用域</h1>

<div id="tpn">

</div>


<div>
<p><strong>作用域指的是变量的适用范围。</strong></p>
</div>


<div>
<h2>公用、私有和受保护作用域</h2>

<h3>概念</h3>

<p>在传统的面向对象程序设计中，主要关注于公用和私有作用域。公用作用域中的对象属性可以从对象外部访问，即开发者创建对象的实例后，就可使用它的公用属性。而私有作用域中的属性只能在对象内部访问，即对于外部世界来说，这些属性并不存在。这意味着如果类定义了私有属性和方法，则它的子类也不能访问这些属性和方法。</p>

<p>受保护作用域也是用于定义私有的属性和方法，只是这些属性和方法还能被其子类访问。</p>

<h3>ECMAScript 只有公用作用域</h3>

<p>对 ECMAScript 讨论上面这些作用域几乎毫无意义，因为 ECMAScript 中只存在一种作用域 - 公用作用域。ECMAScript 中的所有对象的所有属性和方法都是公用的。因此，定义自己的类和对象时，必须格外小心。记住，所有属性和方法默认都是公用的！</p>

<h3>建议性的解决方法</h3>

<p>许多开发者都在网上提出了有效的属性作用域模式，解决了 ECMAScript 的这种问题。</p>

<p>由于缺少私有作用域，开发者确定了一个规约，说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线：</p>

<pre>obj._color_ = &quot;blue&quot;;</pre>

<p>这段代码中，属性 color 是私有的。注意，下划线并不改变属性是公用属性的事实，它只是告诉其他开发者，应该把该属性看作私有的。</p>

<p>有些开发者还喜欢用单下划线说明私有成员，例如：obj._color。</p>
</div>


<div>
<h2>静态作用域</h2>

<p>静态作用域定义的属性和方法任何时候都能从同一位置访问。在 Java 中，类可具有属性和方法，无需实例化该类的对象，即可访问这些属性和方法，例如 java.net.URLEncoder 类，它的函数 encode() 就是静态方法。</p>

<h3>ECMAScript 没有静态作用域</h3>

<p>严格来说，ECMAScript 并没有静态作用域。不过，它可以给构造函数提供属性和方法。还记得吗，构造函数只是函数。函数是对象，对象可以有属性和方法。例如：</p>

<pre>
function sayHello() {
  alert(&quot;hello&quot;);
}

sayHello.alternate = function() {
  alert(&quot;hi&quot;);
}

sayHello();		<span>//输出 &quot;hello&quot;</span>
sayHello.alternate();	<span>//输出 &quot;hi&quot;</span>
</pre>

<p class="tiy"><a target="_blank" href="/tiy/t.asp?f=jseg_pro_object_scope_static">TIY</a></p>

<p>这里，方法 alternate() 实际上是函数 sayHello 的方法。可以像调用常规函数一样调用 sayHello() 输出 &quot;hello&quot;，也可以调用 sayHello.alternate() 输出 &quot;hi&quot;。即使如此，alternate() 也是 sayHello() 公用作用域中的方法，而不是静态方法。</p>
</div>


<div>
<h2>关键字 this</h2>

<h3>this 的功能</h3>

<p>在 ECMAScript 中，要掌握的最重要的概念之一是关键字 this 的用法，它用在对象的方法中。关键字 this 总是指向调用该方法的对象，例如：</p>

<pre>
var oCar = new Object;
oCar.color = &quot;red&quot;;
oCar.showColor = function() {
  alert(<code>this.color</code>);
};

oCar.showColor();		<span>//输出 &quot;red&quot;</span>
</pre>

<p class="tiy"><a target="_blank" href="/tiy/t.asp?f=jseg_pro_object_scope_this_1">TIY</a></p>

<p>在上面的代码中，关键字 this 用在对象的 showColor() 方法中。在此环境中，this 等于 oCar。下面的代码与上面的代码的功能相同：</p>

<pre>
var oCar = new Object;
oCar.color = &quot;red&quot;;
oCar.showColor = function() {
  alert(<code>oCar.color</code>);
};

oCar.showColor();		<span>//输出 &quot;red&quot;</span>
</pre>

<p class="tiy"><a target="_blank" href="/tiy/t.asp?f=jseg_pro_object_scope_this_2">TIY</a></p>


<h3>使用 this 的原因</h3>

<p>为什么使用 this 呢？因为在实例化对象时，总是不能确定开发者会使用什么样的变量名。使用 this，即可在任何多个地方重用同一个函数。请思考下面的例子：</p>

<pre>
function showColor() {
  alert(<code>this.color</code>);
};

var oCar1 = new Object;
oCar1.color = &quot;red&quot;;
oCar1.showColor = showColor;

var oCar2 = new Object;
oCar2.color = &quot;blue&quot;;
oCar2.showColor = showColor;

oCar1.showColor();		<span>//输出 &quot;red&quot;</span>
oCar2.showColor();		<span>//输出 &quot;blue&quot;</span>
</pre>

<p class="tiy"><a target="_blank" href="/tiy/t.asp?f=jseg_pro_object_scope_this_3">TIY</a></p>

<p>在上面的代码中，首先用 this 定义函数 showColor()，然后创建两个对象（oCar1 和 oCar2），一个对象的 color 属性被设置为 &quot;red&quot;，另一个对象的 color 属性被设置为 &quot;blue&quot;。两个对象都被赋予了属性 showColor，指向原始的 showColor () 函数（注意这里不存在命名问题，因为一个是全局函数，而另一个是对象的属性）。调用每个对象的 showColor()，oCar1 输出是 &quot;red&quot;，而 oCar2 的输出是 &quot;blue&quot;。这是因为调用 oCar1.showColor() 时，函数中的 this 关键字等于 oCar1。调用 oCar2.showColor() 时，函数中的 this 关键字等于 oCar2。</p>

<p>注意，引用对象的属性时，必须使用 this 关键字。例如，如果采用下面的代码，showColor() 方法不能运行：</p>

<pre>
function showColor() {
  alert(<code>color</code>);
};
</pre>

<p>如果不用对象或 this 关键字引用变量，ECMAScript 就会把它看作局部变量或全局变量。然后该函数将查找名为 color 的局部或全局变量，但是不会找到。结果如何呢？该函数将在警告中显示 &quot;null&quot;。</p>
</div>


<div id="bpn">

</div>




</div>
